#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <cstring>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
using namespace std;

#include "protocal.h"
#define backlog 5

void *Rountine(void *arg)
{
    // 线程分离，不需要再 wait
    pthread_detach(pthread_self());
    int sock = *(int *)arg;
    delete (int *)arg;

    while (1)
    {
        request req;
        ssize_t n = recv(sock, &req, sizeof(req), 0);
        if (n > 0)
        {
            // 进行计算任务
            response res = {0, 0};
            switch (req.op)
            {
            case '+':
                res.result = req.x + req.y;
                break;
            case '-':
                res.result = req.x - req.y;
                break;
            case '*':
                res.result = req.x * req.y;
                break;
            case '/':
                if (req.y == 0)
                {
                    res.code = 1;
                }
                else
                {
                    res.result = req.x / req.y;
                }
                break;
            case '%':
                if (req.y == 0)
                {
                    res.code = 2;
                }
                else
                {
                    res.result = req.x % req.y;
                }
                break;
            default:
                res.code = 3;
                break;
            }

            // 将结果发送回客户端
            send(sock, &res, sizeof(res), 0);
        }
        else if (n == 0)
        {
            // 对端停止发送数据，退出了
            cout << "Client quit,me too!" << endl;
            break;
        }
        else
        {
            cerr << "recv error!" << endl;
            break;
        }
    }
    close(sock);
    return nullptr; // 返回结果
}

// ./server 8080
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        cerr << "Usage: " << argv[0] << "port" << endl;
        exit(1);
    }
    int port = atoi(argv[1]);
    // 1、创建套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    if (listen_sock < 0)
    {
        cerr << "listen_sock error!" << endl;
        exit(2);
    }
    // 2、绑定
    struct sockaddr_in local;
    memset(&local, 0, sizeof(local));
    local.sin_family = AF_INET;
    local.sin_addr.s_addr = htonl(INADDR_ANY); // 主机转网络
    local.sin_port = htons(port);

    if (bind(listen_sock, (struct sockaddr *)&local, sizeof(local)) < 0)
    {
        cerr << "bind fail!" << endl;
        exit(3);
    }

    // 3、设置监听状态
    if (listen(listen_sock, backlog) < 0)
    {
        cerr << "listen fail!" << endl;
        exit(4);
    }
    // 4、启动服务器
    struct sockaddr_in peer;
    memset(&peer, 0, sizeof(peer));
    for (;;)
    {
        socklen_t socklen = sizeof(peer);
        // 一直获取新连接
        int sock = accept(listen_sock, (struct sockaddr *)&peer, &socklen);
        if (sock < 0)
        {
            cerr << "accept fail!" << endl;
            continue; // 继续获取新连接
        }
        // 创建新线程
        pthread_t tid = 0;
        int *p = new int(sock);
        pthread_create(&tid, nullptr, Rountine, p); // 回调函数，将sock作为参数传递
    }

    return 0;
}